/*******************************************************************************
 * Copyright (c) 2010 L.Carbonnaux.
 *******************************************************************************/

package org.lcx.taskvision.core;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
import org.eclipse.osgi.util.NLS;
import org.lcx.taskvision.core.handler.TaskVisionTaskDataHandler;

/**
 * @author Laurent Carbonnaux
 */
public class TaskVisionRepositoryConnector extends AbstractRepositoryConnector {

	public TaskVisionRepositoryConnector() {
		TaskVisionTaskDataHandler taskDataHandler = new TaskVisionTaskDataHandler(this);
		this.setTaskDataHandler(taskDataHandler);
	}
	
	private TaskVisionClientManager clientManager;
	
	private TaskVisionTaskDataHandler taskDataHandler;

	public void setTaskDataHandler(TaskVisionTaskDataHandler taskDataHandler) {
		this.taskDataHandler = taskDataHandler;
	}

	@Override
	public TaskVisionTaskDataHandler getTaskDataHandler() {
		if(taskDataHandler==null) {
			taskDataHandler = new TaskVisionTaskDataHandler(this);
		}
		return taskDataHandler;
	}

	@Override
	public boolean canCreateNewTask(TaskRepository repository) {
		return true;
	}

	@Override
	public boolean canCreateTaskFromKey(TaskRepository repository) {
		return false;
	}
	
	/**
	 * Whether the connector can delete the task on the Task Repository
	 * @since Mylyn 3.3
	 */
	public boolean canDeleteTask(TaskRepository repository, ITask task) {
		return true;
	}
	
	/**
	 * Retrieve the worksheet url for the given task
	 * Used by mylyn to open the task in the web browser
	 */
	@Override
	public String getTaskUrl(String repositoryUrl, String taskId) {
		//String taskUrl = repositoryUrl + IScrumVisionClient.TASK_URL_PREFIX + taskId;
		int begin = ITaskVisionClient.GOOGLE_WORKSHEETS_PREFIX.length() + 
					repositoryUrl.indexOf(ITaskVisionClient.GOOGLE_WORKSHEETS_PREFIX);
		int end = repositoryUrl.indexOf("/", begin);
		
		String worksheetKey = repositoryUrl.substring(begin, end);
		String worksheetUrl = ITaskVisionClient.GOOGLE_SPREADSHEET_PREFIX + worksheetKey;

		return worksheetUrl;
	}
	
	@Override
	public String getRepositoryUrlFromTaskUrl(String taskFullUrl) {
		int i = taskFullUrl.indexOf(ITaskVisionClient.TASK_URL_PREFIX);
		if(i>0){
			return taskFullUrl.substring(0, i);
		}
		return null;
	}
	
	@Override
	public String getTaskIdFromTaskUrl(String taskFullUrl) {
		int i = taskFullUrl.lastIndexOf(ITaskVisionClient.TASK_URL_PREFIX);
		if(i>0){
			return taskFullUrl.substring(i+ITaskVisionClient.TASK_URL_PREFIX.length(), taskFullUrl.length());
		}
		return null;
	}

	public TaskVisionClientManager getClientManager() {
		if (clientManager == null) {
			clientManager = new TaskVisionClientManager();
		}
		return clientManager;
	}

	@Override
	public boolean hasTaskChanged(TaskRepository taskRepository, ITask task,
			TaskData taskData) {
		TaskMapper mapper = getTaskMapping(taskData);
			return mapper.hasChanges(task);
	}

	/**
	 * Called when synchronization of one task is requested
	 */
	@Override
	public TaskData getTaskData(TaskRepository repository, String taskId,
			IProgressMonitor monitor) throws CoreException {
		try {
			monitor.beginTask(Messages.ScrumVisionRepositoryConnector_synchronize_task, IProgressMonitor.UNKNOWN);
			
			TaskVisionClient client = getClientManager().getClient(repository);
			return client.getTaskData(repository, taskId, monitor);
		} catch (OperationCanceledException e) {
			throw e;
		} catch(CoreException ce) {
			ce.printStackTrace();
			throw ce;
		} catch (Exception e) {
			throw new CoreException(new Status(Status.ERROR, TaskVisionCorePlugin.PLUGIN_ID, Status.ERROR,
					NLS.bind(Messages.ScrumVisionRepositoryConnector_synchronize_task_Error,taskId,e.getMessage()), e));
		} finally {
			monitor.done();
		}
	}
	
	/**
	 * Called when synchronization of all query or new query is requested
	 */
	@Override
	public IStatus performQuery(TaskRepository repository,
			IRepositoryQuery query, TaskDataCollector resultCollector,
			ISynchronizationSession event, IProgressMonitor monitor) {
		try{
			monitor.beginTask(Messages.ScrumVisionRepositoryConnector_running_query, IProgressMonitor.UNKNOWN);
	
			TaskVisionClient client = getClientManager().getClient(repository);
			client.performQuery(repository, query, resultCollector, monitor);
			return Status.OK_STATUS;
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			return new Status(IStatus.ERROR, TaskVisionCorePlugin.PLUGIN_ID, Status.ERROR,
					NLS.bind(Messages.ScrumVisionRepositoryConnector_running_query_Error,e.getMessage()), e);
		} finally {
			monitor.done();
		}
	}

	@Override
	public void updateRepositoryConfiguration(TaskRepository repository,
			IProgressMonitor monitor) throws CoreException {
	}

	@Override
	public void updateTaskFromTaskData(TaskRepository repository, ITask task,
			TaskData taskData) {
		TaskMapper mapper = getTaskMapping(taskData);
		mapper.applyTo(task);
		task.setUrl(this.getTaskUrl(repository.getUrl(), taskData.getTaskId()));
	}

	@Override
	public TaskVisionTaskMapper getTaskMapping(TaskData taskData) {
		return new TaskVisionTaskMapper(taskData);
	}
	
	@Override
	public boolean canSynchronizeTask(TaskRepository taskRepository, ITask task) {
		return true;
	}
	
	/**
	 * Delete the task from the server
	 * 
	 * @since Mylyn 3.3
	 */
	public IStatus deleteTask(TaskRepository repository, ITask task, IProgressMonitor monitor) throws CoreException {
		try {
			monitor.beginTask(Messages.ScrumVisionRepositoryConnector_delete_task, IProgressMonitor.UNKNOWN);
			
			TaskVisionClient client = getClientManager().getClient(repository);
			client.deleteTaskData(task.getTaskId());
			return new Status(IStatus.OK, TaskVisionCorePlugin.PLUGIN_ID,
					Messages.ScrumVisionRepositoryConnector_deletion_ok);
		} catch (OperationCanceledException e) {
			throw e;
		} catch(CoreException ce) {
			ce.printStackTrace();
			throw ce;
		} finally {
			monitor.done();
		}
	}
	
	@Override
	public String getConnectorKind() {
		return TaskVisionCorePlugin.CONNECTOR_KIND;
	}

	@Override
	public String getLabel() {
		return TaskVisionCorePlugin.CLIENT_LABEL;
	}
}
